fix: stop pinning live DataLoaders in quantized model state - #20
Merged
Adithya-Thonse merged 4 commits intoAug 6, 2026
Merged
Conversation
…rt deepcopy
TinyMLQuantFxBaseModule stored the full qconfig_type dict (including the
raw calibration/eval DataLoader objects auto-quantization embeds for its
one-time bitwidth search) as self.qconfig_type, permanently reachable from
the wrapped model. With persistent_workers=True and workers already spun
up, copy.deepcopy(model) in export_model() would then hit a live
_MultiProcessingDataLoaderIter and crash with
NotImplementedError: ('{} cannot be pickled', '_MultiProcessingDataLoaderIter').
Drop the dataloader references from self.qconfig_type once the
auto-quantization search has consumed them, since nothing reads them
afterward.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… CI on its changes The regression test added for the DataLoader-pinning fix (tinyml-modeloptimization/torchmodelopt/tests/test_quant_base_dataloader_leak.py) was never executed by CI: the workflow only triggered on tinyml-modelmaker/** paths and had no step to run torchmodelopt's own tests. A change reintroducing this bug could merge without any red check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
self.qconfig_type = qconfig_type is a reference assignment, so the wrapper
module's dict and the caller's dict were the same object. The subsequent
.pop('calibration_dataloader')/.pop('eval_dataloader') therefore mutated
whatever dict the caller passed in, not just the wrapper's own copy -- a
caller that constructs qconfig_type once and reuses or reads it after
construction would see it silently emptied by a constructor call it
doesn't own. Copy before popping.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
Author
|
CI failure investigated — pre-existing on Verified directly against This PR's CI run shows only that same subset — no new failures introduced. It's fixed in #19; should resolve automatically once that merges. (Windows failures don't block merging — the workflow marks that runner |
This was referenced Jul 30, 2026
…ng-fix # Conflicts: # .github/workflows/test-modelmaker.yml
musicalplatypus
force-pushed
the
pr/dataloader-pinning-fix
branch
from
August 6, 2026 04:37
426f3a0 to
21ffd1d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TinyMLQuantFxBaseModulestored the fullqconfig_typedict — including the raw calibration/evalDataLoaderobjects auto-quantization embeds for its one-time bitwidth search — asself.qconfig_type, permanently reachable from the wrapped model.Root cause
With
persistent_workers=Trueand workers already spun up,copy.deepcopy(model)inexport_model()hits a live_MultiProcessingDataLoaderIterand crashes:A second, related bug found while fixing the first:
self.qconfig_type = qconfig_typeis a reference assignment, so the wrapper module's dict and the caller's dict were the same object. The subsequent.pop('calibration_dataloader')/.pop('eval_dataloader')mutated whatever dict the caller passed in, not just the wrapper's own copy — a caller that constructsqconfig_typeonce and reuses or reads it afterward would see it silently emptied by a constructor call it doesn't own.Fix
self.qconfig_typeonce the auto-quantization search has consumed them, since nothing reads them afterward.qconfig_typebefore popping from it, so the caller's own dict is never mutated.tinyml-modeloptimization/torchmodeloptinto CI: the regression test for this was never actually executed — the workflow only triggered ontinyml-modelmaker/**paths and had no step to run torchmodelopt's own tests, so a regression here could merge without a red check.Verification
Added
test_quant_base_dataloader_leak.py, covering both the deepcopy-after-export crash and the caller-dict-mutation case.Note: the CI workflow change here touches
.github/workflows/test-modelmaker.yml, which two of my other open PRs (pr/test-ci-hygiene,pr/mps-eval-fixes) also touch — each adds a path-trigger/step at the same position. If merged after either, GitHub will show a trivial conflict; the correct resolution is keeping all the added lines (a union), not choosing one over the other.🤖 Generated with Claude Code